package scarlett;

import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * A class that encapsulates all of the logic for comparing two data instances in the Scarlett language.
 * @author Chris Douglass
 * @date 2011-05-05 (Cinco de Mayo baby!)
 */
public class ScarlettComparator {
	
	private final boolean _debug = true;

	/**
	 * Checks if the two objects are equal (the same).
	 * Currently supports Strings only.
	 * @param a the first object
	 * @param b the second object
	 * @return true if they are equal, false if they are not or if the types are not handled by this method
	 */
	public boolean isSameAs(Object a, Object b) {
		/*
		 * TODO: Implement this for all other possible types.
		 */
		if(a instanceof String && b instanceof String)
			return ((String) a).equals((String) b);
		if(_debug) _showError(a, b);
		return false;
	}

	/**
	 * Checks if the first argument is an instance of the given pattern.
	 * Supports Strings only. Applies the given pattern to the first argument and returns if it fits.
	 * @param a
	 * @param b
	 * @return true if the first argument is an instance of the pattern, false if it is not or the object is not a String.
	 */
	public boolean isA(Object a, Pattern b) {
		/*
		 * TODO: This doesn't work quite right. I think it has something to do with
		 * particular regexs.  "everything" seems to work alright here, but email doesn't.
		 * :(
		 */
		if(a instanceof String) {
			return b.matcher((String) a).matches();
		}
		if(a instanceof Integer && b.toString().contains("\\d")) {
			
			// \d is regex for digit
			// yes, it's a number, return true
			return true;
		}
		if(_debug) _showError(a, b);
		return false;
	}

	/**
	 * Checks if the first argument contains the second.
	 * Supports two Strings and a String and regular expression.
	 * @param a
	 * @param b
	 * @return true if the first argument contains the second, false if it does not or the objects cannot be compared.
	 */
	public boolean contains(Object a, Object b) {
		/*
		 * Use matcher(sourceString) & m.find() to see if there are any results
		 * when doing it with regular expressions.  Otherwise just use contains on the string.
		 */
		if(a instanceof String) {
			if(b instanceof String) {
				// Do string contains string
				return ((String) a).contains((String) b);
			}
			else if(b instanceof Pattern) {
				// Do find with a matcher from the pattern
				return ((Pattern) b).matcher((String) a).find();
			}
		}
		/*
		 * If we have a collection and a string, then search the collection
		 * for a matching string and return true.  Otherwise return false.
		 */
		else if(a instanceof Collection && b instanceof String) {
			Collection<?> collection = (Collection<?>) a;
			for(Object o : collection) {
				if(o instanceof String) {
					if(((String) o).equals(b)) return true;
				}
			}
			return false;
		}
		if(_debug) _showError(a, b);
		return false;
	}

	/**
	 * Checks if the first object is larger than the second.
	 * @param a the first object
	 * @param b the second object
	 * @return true if the first object is larger than the second, false if not or the objects are of unsupported or unmatched types
	 */
	public boolean isLargerThan(Object a, Object b) {
		/*
		 * TODO: Are there other types than Strings and Collections I have to handle?
		 */
		if(a instanceof String) {
			if(b instanceof String) {
				return ((String) a).length() > ((String) b).length();
			}
		}
		else if(a instanceof Collection) {
			if(b instanceof Collection) {
				return ((Collection<?>) a).size() > ((Collection<?>) b).size();
			}
		}
		if(_debug) _showError(a, b);
		return false;
	}

	/**
	 * Checks if the first object is smaller than the second.
	 * @param a the first object
	 * @param b the second object
	 * @return true if the first object is smaller than the second, false if not or the objects are of unsupported or unmatched types
	 */
	public boolean isSmallerThan(Object a, Object b) {
		if(a instanceof String) {
			if(b instanceof String) {
				return ((String) a).length() < ((String) b).length();
			}
		}
		else if(a instanceof Collection) {
			if(b instanceof Collection) {
				return ((Collection<?>) a).size() < ((Collection<?>) b).size();
			}
		}
		if(_debug) _showError(a, b);
		return false;
	}
	
	private void _showError(Object a, Object b) {
		System.out.println("**COMPARATOR ERROR**: Could not handle objects with types: " + a.getClass().getName() + " & " + b.getClass().getName());
	}
}
